/*
  Copyright 2006 by Sean Luke
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
 */

package ec.app.deferEvalCoevolve1;

import ec.*;
import ec.simple.SimpleProblemForm;
import ec.steadystate.*;
import java.io.IOException;
import ec.util.*;
import java.io.File;

/* 
 * DeferEval_Statistics_simple
 * 
 * Created: Tue Aug 10 21:10:48 1999
 * By: Sean Luke
 */

/**
 * A basic Statistics class suitable for simple problem applications.
 * 
 * DeferEval_Statistics_simple prints out the best individual, per subpopulation, each
 * generation. At the end of a run, it also prints out the best individual of
 * the run. DeferEval_Statistics_simple outputs this data to a log which may either be a
 * provided file or stdout. Compressed files will be overridden on restart from
 * checkpoint; uncompressed files will be appended on restart.
 * 
 * <p>
 * DeferEval_Statistics_simple implements a simple version of steady-state statistics: if it
 * quits before a generation boundary, it will include the best individual
 * discovered, even if the individual was discovered after the last boundary.
 * This is done by using individualsEvaluatedStatistics(...) to update
 * best-individual-of-generation in addition to doing it in
 * postEvaluationStatistics(...).
 * 
 * <p>
 * <b>Parameters</b><br>
 * <table>
 * <tr>
 * <td valign=top><i>base.</i><tt>gzip</tt><br>
 * <font size=-1>boolean</font></td>
 * <td valign=top>(whether or not to compress the file (.gz suffix added)</td>
 * </tr>
 * <tr>
 * <td valign=top><i>base.</i><tt>file</tt><br>
 * <font size=-1>String (a filename), or nonexistant (signifies stdout)</font></td>
 * <td valign=top>(the log for statistics)</td>
 * </tr>
 * </table>
 * 
 * 
 * @author Sean Luke/Daniel Rothman
 * @version 1.1
 */

public class DeferEval_Statistics_simple extends Statistics implements
		SteadyStateStatisticsForm {
	/** log file parameter */
	public static final String P_STATISTICS_FILE = "file";

	/** compress? */
	public static final String P_COMPRESS = "gzip";

	/** The Statistics' log */
	public int statisticslog;

	/** The best individual we've found so far */
	public Individual[] best_of_run;

	/**
	 * The number of individual trials (One complete team with all subpops
	 * represented, vs. a second team)
	 */
	// public int trials = 0;
	public DeferEval_Statistics_simple() {
		best_of_run = null;
		statisticslog = 0; /* stdout */
		// trials = 0;
	}

	/**
	 * @return the trials
	 */
	// public int getTrials() {
	// return trials;
	// }
	/**
	 * @param trials
	 *            the trials to set
	 */
	// public void setTrials(int trials) {
	// this.trials = trials;
	// }
	/**
	 * @return the (new) trials
	 */
	// public int incrementTrials() {
	// return( ++trials );
	// }
	public void setup(final EvolutionState state, final Parameter base) {
		super.setup(state, base);

		File statisticsFile = state.parameters.getFile(base
				.push(P_STATISTICS_FILE), null);

		if (statisticsFile != null)
			try {
				statisticslog = state.output.addLog(statisticsFile,
						Output.V_NO_GENERAL - 1, false,
						!state.parameters.getBoolean(base.push(P_COMPRESS),
								null, false), state.parameters.getBoolean(base
								.push(P_COMPRESS), null, false));
			} catch (IOException i) {
				state.output
						.fatal("An IOException occurred while trying to create the log "
								+ statisticsFile + ":\n" + i);
			}
	}

	public void postInitializationStatistics(final EvolutionState state) {
		SimpleFitnessVar2.setRunEvalCount( false );
		super.postInitializationStatistics(state);

		// set up our best_of_run array -- can't do this in setup, because
		// we don't know if the number of subpopulations has been determined yet
		best_of_run = new Individual[state.population.subpops.length];

		SimpleFitnessVar2.setRunEvalCount( true );
	}

	/** Logs the best individual of the generation. */
	public void postEvaluationStatistics(final EvolutionState state) {
		SimpleFitnessVar2.setRunEvalCount( false );
		super.postEvaluationStatistics(state);
		
		// for now we just print the best fitness per subpopulation.
		Individual[] best_i = new Individual[state.population.subpops.length]; // quiets compiler complaints
		for (int x = 0; x < state.population.subpops.length; x++) {
			best_i[x] = state.population.subpops[x].individuals[0];
			// TODO find a happy way to move the selectionmethod stuff up in the
			// chain...
			DeferEval_TournamentSelection_simple sel = (DeferEval_TournamentSelection_simple) ((MPCoevoEvalVar2) (state.evaluator)).selectionMethod[x];
			int tmpIndex = -1;
			tmpIndex = sel.produce(x, state, 0);
			best_i[x] = state.population.subpops[x].individuals[tmpIndex];
			// for(int y=1;y<state.population.subpops[x].individuals.length;y++)
			// if
			// (state.population.subpops[x].individuals[y].fitness.betterThan(best_i[x].fitness))
			// best_i[x] = state.population.subpops[x].individuals[y];

			// now test to see if it's the new best_of_run
			boolean tmpTest = false;
			if (best_of_run[x] == null) {
				tmpTest = true;
			} else { // actually do the test with a non-null bloke..
				tmpTest = sel.evaluation(state, state.population.subpops[x],
						best_i[x], best_of_run[x]);
			}
			if (best_of_run[x] == null || tmpTest)
				best_of_run[x] = (Individual) (best_i[x].clone());
			// if (best_of_run[x]==null ||
			// best_i[x].fitness.betterThan(best_of_run[x].fitness))
			// best_of_run[x] = (Individual)(best_i[x].clone());
		}

		// print the best-of-generation individual
		state.output.println("\nGeneration: " + state.generation,
				Output.V_NO_GENERAL, statisticslog);
//		state.output.println("Best Individual:", Output.V_NO_GENERAL, statisticslog);
		for (int x = 0; x < state.population.subpops.length; x++) {
			state.output.print("Pop: " + x + "\t", Output.V_NO_GENERAL,
					statisticslog);
			best_i[x].printIndividualForHumans(state, statisticslog,
					Output.V_NO_GENERAL);
			state.output.message("Subpop " + x
					+ " best fitness of generation: "
					+ best_i[x].fitness.fitnessToStringForHumans());
		}
		SimpleFitnessVar2.setRunEvalCount( true );
	}

	/** Logs the best individual of the run. */
	public void finalStatistics(final EvolutionState state, final int result) {
		SimpleFitnessVar2.setRunEvalCount( false );
		super.finalStatistics(state, result);

		// for now we just print the best fitness

		state.output.println("\nBest Individual of Run:", Output.V_NO_GENERAL,
				statisticslog);
		for (int x = 0; x < state.population.subpops.length; x++) {
			best_of_run[x].printIndividualForHumans(state, statisticslog,
					Output.V_NO_GENERAL);
			// best_of_run[x].printIndividual(state,statisticslog,Output.V_NO_GENERAL);
			state.output.message("Subpop " + x + " best fitness of run: "
					+ best_of_run[x].fitness.fitnessToStringForHumans());
			int trial_count = 0;
			trial_count = DeferEval_Comparator_base.getTrialCount();
			state.output.message("total trials: " + trial_count);
			state.output.println("total trials: :" + trial_count,
					Output.V_NO_GENERAL, statisticslog);

			// finally describe the winner if there is a description
			if (state.evaluator.p_problem instanceof SimpleProblemForm)
				((SimpleProblemForm) (state.evaluator.p_problem.clone()))
						.describe(best_of_run[x], state, x, 0, statisticslog,
								Output.V_NO_GENERAL);
		}

		DeferEval_Comparator_base.resetTrialCount();
		SimpleFitnessVar2.resetEvalCount();
		SimpleFitnessVar2.setRunEvalCount( true );
	}
}
